package com.github.zzay.news.controller;

import com.github.zzay.common.core.model.ResponseBean;
import com.github.zzay.common.core.annotation.MyRateLimit;
import com.github.zzay.common.core.exception.SystemException;
import com.github.zzay.news.entity.News;
import com.github.zzay.news.dto.NewsDto;
import com.github.zzay.news.service.NewsService;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

/**
 * @author zzay
 * @className NewsController
 * @description News Controller
 * @create 2022/05/01 14:12
 */
@RestController
@RequestMapping("/news")
@DefaultProperties(defaultFallback = "newsGlobalFallback")
@Tag(name = "NewsController", description = "新闻信息操作相关接口")
public class NewsController {

    /**
     * News Service
     */
    @Autowired
    private NewsService newsService;

    /**
     * Kafka Template
     */
    @Autowired
    private KafkaTemplate<String, Object> kafkaTemplate;

    /**
     * Management page
     *
     * @param newsDto News DTO
     * @return Management page
     */
    @Operation(summary = "新闻管理页面跳转", description = "新闻管理页面跳转",
            security = @SecurityRequirement(name = HttpHeaders.AUTHORIZATION))
    @ApiResponse(responseCode = "200", description = "成功跳转到新闻管理页面")
    @MyRateLimit(key = "limit_managementPage", permitsPerSecond = 1, timeout = 500, msg = "系统繁忙，请稍后再尝试！")
    @HystrixCommand(fallbackMethod = "managementPageFallback",
            commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")})
    @PreAuthorize("hasAuthority('system:admin')")
    @GetMapping("/management")
    public ResponseBean managementPage(@Parameter(name = "newsDto") @RequestBody NewsDto newsDto) {
        Map<String, Object> data = new HashMap<>();
        Integer page = newsDto.getPage();
        if (page == null) {
            data.put("list", newsService.getListByPage(1));
            data.put("pageNum", 1);
        } else {
            data.put("list", newsService.getListByPage(page));
            data.put("pageNum", page);
        }
        data.put("page", newsService.getPublishedPageCount());
        return new ResponseBean(HttpStatus.OK.value(), "Go to management page", data);
    }

    /**
     * Create page
     *
     * @return Create page
     */
    @Operation(summary = "新闻创建页面跳转", description = "新闻创建页面跳转",
            security = @SecurityRequirement(name = HttpHeaders.AUTHORIZATION))
    @ApiResponse(responseCode = "200", description = "成功跳转到新闻创建页面")
    @MyRateLimit(key = "limit_createPage", permitsPerSecond = 1, timeout = 500, msg = "系统繁忙，请稍后再尝试！")
    @HystrixCommand(fallbackMethod = "createPageFallback",
            commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")})
    @GetMapping("/create")
    public ResponseBean createPage() {
        Map<String, Object> data = new HashMap<>();
        return new ResponseBean(HttpStatus.OK.value(), "Go to news-create page", data);
    }

    /**
     * Edit page
     *
     * @param newsDto News DTO
     * @return Edit page
     */
    @Operation(summary = "新闻编辑页面跳转", description = "新闻编辑页面跳转",
            security = @SecurityRequirement(name = HttpHeaders.AUTHORIZATION))
    @ApiResponse(responseCode = "200", description = "成功跳转到新闻编辑页面")
    @MyRateLimit(key = "limit_editPage", permitsPerSecond = 1, timeout = 500, msg = "系统繁忙，请稍后再尝试！")
    @HystrixCommand(fallbackMethod = "editPageFallback",
            commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")})
    @PreAuthorize("hasAuthority('system:admin')")
    @GetMapping("/edit")
    public ResponseBean editPage(@Parameter(name = "newsDto") @RequestBody NewsDto newsDto) {
        Map<String, Object> data = new HashMap<>();
        Integer id = newsDto.getId();
        News news = newsService.getNewsById(id);
        data.put("news", news);
        return new ResponseBean(HttpStatus.OK.value(), "Go to news-edit page", data);
    }

    /**
     * Audit page
     *
     * @param newsDto News DTO
     * @return Audit page
     */
    @Operation(summary = "新闻审核页面跳转", description = "新闻审核页面跳转",
            security = @SecurityRequirement(name = HttpHeaders.AUTHORIZATION))
    @ApiResponse(responseCode = "200", description = "成功跳转到新闻审核页面")
    @MyRateLimit(key = "limit_auditPage", permitsPerSecond = 1, timeout = 500, msg = "系统繁忙，请稍后再尝试！")
    @HystrixCommand(fallbackMethod = "auditPageFallback",
            commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")})
    @PreAuthorize("hasAuthority('system:admin')")
    @GetMapping("/audit")
    public ResponseBean auditPage(@Parameter(name = "newsDto") @RequestBody NewsDto newsDto) {
        Map<String, Object> data = new HashMap<>();
        // if not given a page number, go to the first page by default
        Integer page = newsDto.getPage();
        if (page == null) {
            data.put("list", newsService.getUnpublishedList(1));
            data.put("pageNum", 1);
        } else {
            data.put("list", newsService.getListByPage(page));
            data.put("pageNum", page);
        }
        data.put("page", newsService.getUnpublishedPageCount());
        return new ResponseBean(HttpStatus.OK.value(), "Go to news-audit page", data);
    }

    /**
     * Display news on news page
     *
     * @param newsDto News DTO
     * @return News page
     * @throws SystemException
     */
    @Operation(summary = "展示新闻页面", description = "展示新闻页面：用户通过点击对应新闻传入对应新闻的ID，展示对应的新闻页面",
            security = @SecurityRequirement(name = HttpHeaders.AUTHORIZATION))
    @ApiResponse(responseCode = "200", description = "跳转到对应的新闻页面")
    @HystrixCommand(fallbackMethod = "displayNewsByIdFallback",
            commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")})
    @MyRateLimit(key = "limit_dashboard", permitsPerSecond = 1, timeout = 500, msg = "系统繁忙，请稍后再查看！")
    @GetMapping("/getById")
    public ResponseBean displayNewsById(@Parameter(name = "newsDto") @RequestBody NewsDto newsDto) throws SystemException {
        Map<String, Object> data = new HashMap<>();
        Integer id = newsDto.getId();
        News news = newsService.getNewsById(id);
        if (news == null) {
            throw new SystemException("Failed to access because the server is being maintained, please retry later !");
        }
        data.put("news", news);
        return new ResponseBean(HttpStatus.OK.value(), "Go to news-display page", data);
    }

    /**
     * Edit news
     *
     * @param newsDto News DTO
     * @return Management page
     * @throws SystemException
     */
    @Operation(summary = "编辑新闻", description = "编辑新闻：用户在编辑新闻页面编辑新闻",
            security = @SecurityRequirement(name = HttpHeaders.AUTHORIZATION))
    @ApiResponse(responseCode = "200", description = "成功编辑新闻，跳转到新闻管理页面")
    @MyRateLimit(key = "limit_doEdit", permitsPerSecond = 1, timeout = 500, msg = "系统繁忙，请稍后再尝试！")
    @HystrixCommand(fallbackMethod = "editNewsFallback",
            commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")})
    @PreAuthorize("hasAuthority('system:admin')")
    @PostMapping("/doEdit")
    public ResponseBean editNews(@Parameter(name = "newsDto") @RequestBody NewsDto newsDto, String callbackMsg) throws SystemException {
        Map<String, Object> data = new HashMap<>();
        kafkaTemplate.send("editNews", callbackMsg).addCallback(success -> {
            // Get topic
            String topic = success.getRecordMetadata().topic();
            // Get partition
            int partition = success.getRecordMetadata().partition();
            // Get offset of the topic in the partition
            long offset = success.getRecordMetadata().offset();
            System.out.println("发送消息成功:" + topic + "-" + partition + "-" + offset);
        }, failure -> System.out.println("发送消息失败:" + failure.getMessage()));
        if (!newsService.editNews(newsDto)) {
            throw new SystemException("Failed to edit because the server is being maintained, please retry later !");
        }
        data.put("list", newsService.getListByPage(1));
        data.put("pageNum", 1);
        data.put("page", newsService.getPublishedPageCount());
        return new ResponseBean(HttpStatus.OK.value(), "Successfully edit the news, go to management page", data);
    }

    /**
     * Audit news
     *
     * @param newsDto News DTO
     * @return Audit page
     * @throws SystemException
     */
    @Operation(summary = "审核新闻", description = "审核新闻：用户通过点击审核新闻页面，审核对应的新闻",
            security = @SecurityRequirement(name = HttpHeaders.AUTHORIZATION))
    @ApiResponse(responseCode = "200", description = "成功审核新闻，跳转到新闻审核页面")
    @MyRateLimit(key = "limit_doAudit", permitsPerSecond = 1, timeout = 500, msg = "系统繁忙，请稍后再尝试！")
    @HystrixCommand(fallbackMethod = "auditNewsFallback",
            commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")})
    @PreAuthorize("hasAuthority('system:admin')")
    @GetMapping("/doAudit")
    public ResponseBean auditNews(@Parameter(name = "newsDto") @RequestBody NewsDto newsDto) throws SystemException {
        Map<String, Object> data = new HashMap<>();
        Integer id = newsDto.getId();
        if (!newsService.publishNews(id)) {
            throw new SystemException("Failed to audit because the server is being maintained, please retry later !");
        }
        data.put("list", newsService.getUnpublishedList(1));
        data.put("pageNum", 1);
        data.put("page", newsService.getUnpublishedPageCount());
        return new ResponseBean(HttpStatus.OK.value(), "Successfully audit the news, go to audit-page", data);
    }

    /**
     * Delete news
     *
     * @param newsDto News DTO
     * @return Management page
     * @throws SystemException
     */
    @Operation(summary = "删除新闻", description = "删除新闻：用户通过点击删除新闻按钮，删除对应的新闻",
            security = @SecurityRequirement(name = HttpHeaders.AUTHORIZATION))
    @ApiResponse(responseCode = "200", description = "成功删除新闻，跳转到新闻管理页面")
    @MyRateLimit(key = "limit_delete", permitsPerSecond = 1, timeout = 500, msg = "系统繁忙，请稍后再尝试！")
    @HystrixCommand(fallbackMethod = "deleteNewsFallback",
            commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")})
    @PreAuthorize("hasAuthority('system:admin')")
    @GetMapping("/delete")
    public ResponseBean deleteNews(@Parameter(name = "newsDto") @RequestBody NewsDto newsDto) throws SystemException {
        Map<String, Object> data = new HashMap<>();
        Integer id = newsDto.getId();
        if (!newsService.deleteNews(id)) {
            throw new SystemException("Failed to delete because the server is being maintained, please retry later !");
        }
        // after deletion, jump to the first page
        data.put("list", newsService.getListByPage(1));
        data.put("pageNum", 1);
        data.put("page", newsService.getPublishedPageCount());
        return new ResponseBean(HttpStatus.OK.value(), "Successfully delete the news, go to management page", data);
    }

}
